home *** CD-ROM | disk | FTP | other *** search
/ CICA 1995 August / CICA - The Ultimate Collection of Shareware for Windows (Disc 2) (August 1995).iso / disc2 / nt / source.exe / POSIX / ELVIS / CURSES.C < prev    next >
C/C++ Source or Header  |  1993-07-06  |  16KB  |  770 lines

  1. /* curses.c */
  2.  
  3. /* Author:
  4.  *    Steve Kirkendall
  5.  *    14407 SW Teal Blvd. #C
  6.  *    Beaverton, OR 97005
  7.  *    kirkenda@cs.pdx.edu
  8.  */
  9.  
  10.  
  11. /* This file contains the functions & variables needed for a tiny subset of
  12.  * curses.  The principle advantage of this version of curses is its
  13.  * extreme speed.  Disadvantages are potentially larger code, few supported
  14.  * functions, limited compatibility with full curses, and only stdscr.
  15.  */
  16.  
  17. #include "config.h"
  18. #include "vi.h"
  19.  
  20.  
  21. #if ANY_UNIX
  22. # if UNIXV
  23. #  include    <termio.h>
  24. #  undef    TIOCWINSZ    /* we can't handle it correctly yet */
  25. # else
  26. #  include    <sgtty.h>
  27. # endif
  28. #elif DF_POSIX
  29. #  include    <termios.h>
  30. #endif
  31.  
  32. #if TOS
  33. # include    <osbind.h>
  34. #endif
  35.  
  36. #if OSK
  37. # include    <sgstat.h>
  38. #endif
  39.  
  40. #include <signal.h>
  41.  
  42. extern char    *getenv(const char *);
  43. static void     starttcap();
  44.  
  45. /* variables, publicly available & used in the macros */
  46. short    ospeed;        /* speed of the tty, eg B2400 */
  47. #if OSK
  48. char    PC_;    /* Pad char */
  49. char    *BC;    /* backspace character string */
  50. #else
  51. char    PC;        /* Pad char */
  52. #endif
  53. WINDOW    *stdscr;    /* pointer into kbuf[] */
  54. WINDOW    kbuf[KBSIZ];    /* a very large output buffer */
  55. int    LINES;        /* :li#: number of rows */
  56. int    COLS;        /* :co#: number of columns */
  57. int    AM;        /* :am:  boolean: auto margins? */
  58. int    PT;        /* :pt:  boolean: physical tabs? */
  59. char    *VB;        /* :vb=: visible bell */
  60. char    *UP;        /* :up=: move cursor up */
  61. char    *SO;        /* :so=: standout start */
  62. char    *SE;        /* :se=: standout end */
  63. char    *US = "";    /* :us=: underline start */
  64. char    *UE = "";    /* :ue=: underline end */
  65. char    *MD = "";    /* :md=: bold start */
  66. char    *ME = "";    /* :me=: bold end */
  67. char    *AS;        /* :as=: alternate (italic) start */
  68. char    *AE;        /* :ae=: alternate (italic) end */
  69. char    *CM;        /* :cm=: cursor movement */
  70. char    *CE;        /* :ce=: clear to end of line */
  71. char    *CD;        /* :cd=: clear to end of screen */
  72. char    *AL;        /* :al=: add a line */
  73. char    *DL;        /* :dl=: delete a line */
  74. #if OSK
  75. char    *SR_;        /* :sr=: scroll reverse */
  76. #else
  77. char    *SR;        /* :sr=: scroll reverse */
  78. #endif
  79. char    *KS;        /* :ks=: init string for cursor */
  80. char    *KE;        /* :ke=: restore string for cursor */
  81. char    *KU;        /* :ku=: key sequence sent by up arrow */
  82. char    *KD;        /* :kd=: key sequence sent by down arrow */
  83. char    *KL;        /* :kl=: key sequence sent by left arrow */
  84. char    *KR;        /* :kr=: key sequence sent by right arrow */
  85. char    *HM;        /* :HM=: key sequence sent by the <Home> key */
  86. char    *EN;        /* :EN=: key sequence sent by the <End> key */
  87. char    *PU;        /* :PU=: key sequence sent by the <PgUp> key */
  88. char    *PD;        /* :PD=: key sequence sent by the <PgDn> key */
  89. char    *IM;        /* :im=: insert mode start */
  90. char    *IC = "";    /* :ic=: insert the following character */
  91. char    *EI;        /* :ei=: insert mode end */
  92. char    *DC;        /* :dc=: delete a character */
  93. char    *TI;        /* :ti=: terminal init */    /* GB */
  94. char    *TE;        /* :te=: terminal exit */    /* GB */
  95. #ifndef NO_CURSORSHAPE
  96. char    *CQ = (char *)0;/* :cQ=: normal cursor */
  97. char    *CX = (char *)1;/* :cX=: cursor used for EX command/entry */
  98. char    *CV = (char *)2;/* :cV=: cursor used for VI command mode */
  99. char    *CI = (char *)3;/* :cI=: cursor used for VI input mode */
  100. char    *CR = (char *)4;/* :cR=: cursor used for VI replace mode */
  101. #endif
  102. char    *aend = "";    /* end an attribute -- either UE or ME */
  103. char    ERASEKEY;    /* backspace key taken from ioctl structure */
  104.  
  105. #if ANY_UNIX
  106. # if UNIXV
  107. static struct termio    oldtermio;    /* original tty mode */
  108. static struct termio    newtermio;    /* cbreak/noecho tty mode */
  109. # else
  110. static struct sgttyb    oldsgttyb;    /* original tty mode */
  111. static struct sgttyb    newsgttyb;    /* cbreak/nl/noecho tty mode */
  112. static int        oldint;        /* ^C or DEL, the "intr" character */
  113. #  ifdef TIOCSLTC
  114. static int        oldswitch;    /* ^Z, the "suspend" character */
  115. static int        oldquote;    /* ^V, the "quote next char" char */
  116. #  endif
  117. # endif
  118. #elif DF_POSIX
  119. struct termios    oldtermio;    /* original tty mode */
  120. struct termios    newtermio;    /* cbreak/noecho tty mode */
  121. #endif
  122.  
  123. #if OSK
  124. static struct sgbuf    oldsgttyb;    /* orginal tty mode */
  125. static struct sgbuf    newsgttyb;    /* noecho tty mode */
  126. #endif
  127.  
  128. static char    *capbuf;    /* capability string buffer */
  129.  
  130.  
  131. void initscr()
  132. {
  133.     /* make sure TERM variable is set */
  134. #if MSDOS
  135.     char *val;
  136.     if (! (val = getenv("TERM"))
  137.     || !strcmp(val, "pcbios"))
  138. #else
  139.     if (!getenv("TERM"))
  140. #endif
  141.     {
  142. #if ANY_UNIX || DF_POSIX
  143.         write(2, "Environment variable TERM must be set\n", (unsigned)38);
  144.         exit(1);
  145. #endif
  146. #if OSK
  147.         writeln(2, "Environment variable TERM must be set\n", (unsigned)38);
  148.         exit(1);
  149. #endif
  150. #if MSDOS || TOS
  151.         getsize(0);
  152. #endif
  153.     }
  154.     else
  155.     {
  156. #if MSDOS
  157.         *o_pcbios=0;
  158. #endif
  159.         /* start termcap stuff */
  160.         starttcap();
  161.     }
  162.  
  163.     /* create stdscr and curscr */
  164.     stdscr = kbuf;
  165.  
  166.     /* change the terminal mode to cbreak/noecho */
  167. #if ANY_UNIX
  168. # if UNIXV
  169.     ioctl(2, TCGETA, &oldtermio);
  170. # else
  171.     ioctl(2, TIOCGETP, &oldsgttyb);
  172. # endif
  173. #elif DF_POSIX
  174.     if (tcgetattr(2, &oldtermio) < 0 )
  175.         perror("Could not get tty attributes");
  176.  
  177. //    if (oldtermio.c_lflag & ICANON)
  178. //    printf("icanon\n");
  179. //    if (oldtermio.c_lflag & ECHO)
  180. //    printf("echo\n");
  181. #endif
  182.  
  183. #if OSK
  184.     _gs_opt(0, &oldsgttyb);
  185. #endif
  186.     resume_curses(TRUE);
  187. }
  188.  
  189.  
  190. void endwin()
  191. {
  192.     /* change the terminal mode back the way it was */
  193.     suspend_curses();
  194. }
  195.  
  196.  
  197. static int curses_active = FALSE;
  198.  
  199. void suspend_curses()
  200. {
  201. #if ANY_UNIX && !UNIXV
  202.     struct tchars    tbuf;
  203. # ifdef TIOCSLTC
  204.     struct ltchars    ltbuf;
  205. # endif
  206. #endif
  207. #ifndef NO_CURSORSHAPE
  208.     if (has_CQ)
  209.     {
  210.         do_CQ();
  211.     }
  212. #endif
  213.     if (has_TE)                    /* GB */
  214.     {
  215.         do_TE();
  216.     }
  217.     if (has_KE)
  218.     {
  219.         do_KE();
  220.     }
  221.     refresh();
  222.  
  223.     /* change the terminal mode back the way it was */
  224.  
  225. #if ANY_UNIX
  226. # if UNIXV
  227.     ioctl(2, TCSETAW, &oldtermio);
  228. # else
  229.     ioctl(2, TIOCSETP, &oldsgttyb);
  230.  
  231.     ioctl(2, TIOCGETC, &tbuf);
  232.     tbuf.t_intrc = oldint;
  233.     ioctl(2, TIOCSETC, &tbuf);
  234.  
  235. #  ifdef TIOCSLTC
  236.     ioctl(2, TIOCGLTC, <buf);
  237.     ltbuf.t_suspc = oldswitch;
  238.     ltbuf.t_lnextc = oldquote;
  239.     ioctl(2, TIOCSLTC, <buf);
  240. #  endif
  241. # endif
  242. # elif DF_POSIX
  243.     if (tcsetattr(2, TCSANOW, &oldtermio))
  244.         perror("Could not set old tty attributes");
  245.     
  246. #endif
  247. #if OSK
  248.     _ss_opt(0, &oldsgttyb);
  249. #endif
  250.     curses_active = FALSE;
  251. }
  252.  
  253. void resume_curses(quietly)
  254.     int    quietly;
  255. {
  256.     if (!curses_active)
  257.     {
  258.         /* change the terminal mode to cbreak/noecho */
  259. #if ANY_UNIX
  260. # if UNIXV
  261.         ospeed = (oldtermio.c_cflag & CBAUD);
  262.         ERASEKEY = oldtermio.c_cc[VERASE];
  263.         newtermio = oldtermio;
  264.         newtermio.c_iflag &= (IXON|IXOFF|IXANY|ISTRIP|IGNBRK);
  265.         newtermio.c_oflag &= ~OPOST;
  266.         newtermio.c_lflag &= ISIG;
  267.         newtermio.c_cc[VINTR] = ctrl('C'); /* always use ^C for interrupts */
  268.         newtermio.c_cc[VMIN] = 1;
  269.         newtermio.c_cc[VTIME] = 0;
  270. #  ifdef VSWTCH
  271.         newtermio.c_cc[VSWTCH] = 0;
  272. #  endif
  273.         ioctl(2, TCSETAW, &newtermio);
  274. # else /* BSD or V7 or Coherent or Minix */
  275.         struct tchars    tbuf;
  276. #  ifdef TIOCSLTC
  277.         struct ltchars    ltbuf;
  278. #  endif
  279.  
  280.         ospeed = oldsgttyb.sg_ospeed;
  281.         ERASEKEY = oldsgttyb.sg_erase;
  282.         newsgttyb = oldsgttyb;
  283.         newsgttyb.sg_flags |= CBREAK;
  284.         newsgttyb.sg_flags &= ~(CRMOD|ECHO|XTABS);
  285.         ioctl(2, TIOCSETP, &newsgttyb);
  286.  
  287.         ioctl(2, TIOCGETC, &tbuf);
  288.         oldint = tbuf.t_intrc;
  289.         tbuf.t_intrc = ctrl('C');    /* always use ^C for interrupts */
  290.         ioctl(2, TIOCSETC, &tbuf);
  291.  
  292. #  ifdef TIOCSLTC
  293.         ioctl(2, TIOCGLTC, <buf);
  294.         oldswitch = ltbuf.t_suspc;
  295.         ltbuf.t_suspc = 0;        /* disable ^Z for elvis */
  296.         oldquote = ltbuf.t_lnextc;
  297.         ltbuf.t_lnextc = 0;        /* disable ^V for elvis */
  298.         ioctl(2, TIOCSLTC, <buf);
  299. #  endif
  300.  
  301. # endif
  302. #elif DF_POSIX
  303.         ospeed = cfgetospeed(&oldtermio);
  304.         ERASEKEY = oldtermio.c_cc[VERASE];
  305.         newtermio = oldtermio;
  306. //printf("Soldtermio = %x            \n", oldtermio.c_lflag);
  307.         newtermio.c_iflag |= (IXON|IXOFF|ISTRIP|IGNBRK);
  308.         newtermio.c_oflag &= ~OPOST;
  309.         newtermio.c_lflag &= (~ISIG);
  310.         //newtermio.c_lflag |= ISIG;
  311.         newtermio.c_lflag &= (~ICANON & ~ECHO);
  312. //printf("Snewtermio = %x            \n", newtermio.c_lflag);
  313.         newtermio.c_cc[VINTR] = ctrl('C'); /* always use ^C for interrupts */
  314. //printf("curses.c: setting attr %x            \n", newtermio.c_lflag);
  315. //printf("curses.c: old attr %x            \n", oldtermio.c_lflag);
  316. strcpy(newtermio.c_cc, "TEST");
  317.         if (tcsetattr(2, TCSANOW, &newtermio))
  318.             perror("Could not set new tty attributes");
  319. #endif
  320. #
  321. #if OSK
  322.         newsgttyb = oldsgttyb;
  323.         newsgttyb.sg_echo = 0;
  324.         newsgttyb.sg_eofch = 0;
  325.         newsgttyb.sg_kbach = 0;
  326.         newsgttyb.sg_kbich = ctrl('C');
  327.         _ss_opt(0, &newsgttyb);
  328.         ospeed = oldsgttyb.sg_baud;
  329.         ERASEKEY = oldsgttyb.sg_bspch;
  330. #endif
  331.  
  332.         if (has_TI)                    /* GB */
  333.         {
  334.             do_TI();
  335.         }
  336.         if (has_KS)
  337.         {
  338.             do_KS();
  339.         }
  340.  
  341.         curses_active = TRUE;
  342.     }
  343.  
  344.     /* If we're supposed to quit quietly, then we're done */
  345.     if (quietly)
  346.     {
  347.         return;
  348.     }
  349.  
  350.     signal(SIGINT, SIG_IGN);
  351.  
  352.     move(LINES - 1, 0);
  353.     do_SO();
  354.     qaddstr("[Press <RETURN> to continue]");
  355.     do_SE();
  356.     refresh();
  357.     ttyread(kbuf, 20); /* in RAW mode, so <20 is very likely */
  358.     if (kbuf[0] == ':')
  359.     {
  360.         mode = MODE_COLON;
  361.         addch('\n');
  362.         refresh();
  363.     }
  364.     else
  365.     {
  366.         mode = MODE_VI;
  367.         redraw(MARK_UNSET, FALSE);
  368.     }    
  369.     exwrote = FALSE;
  370.  
  371. #if TURBOC
  372.     signal(SIGINT, (void(*)()) trapint);
  373. #else
  374.     signal(SIGINT, trapint);
  375. #endif
  376. }
  377.  
  378. static void lacking(s)
  379.     char    *s;
  380. {
  381.     write(2, "This termcap entry lacks the :", (unsigned)30);
  382.     write(2, s, (unsigned)2);
  383.     write(2, "=: capability\n", (unsigned)14);
  384. #if OSK
  385.     write(2, "\l", 1);
  386. #endif
  387.     exit(1);
  388. }
  389.  
  390. static void starttcap()
  391. {
  392.     char    *str;
  393.     static char    cbmem[800];
  394. #define MUSTHAVE(T,s)    if (!(T = tgetstr(s, &capbuf))) lacking(s)
  395. #define MAYHAVE(T,s)    if (str = tgetstr(s, &capbuf)) T = str
  396. #define PAIR(T,U,sT,sU)    T=tgetstr(sT,&capbuf);U=tgetstr(sU,&capbuf);if (!T||!U)T=U=""
  397.  
  398.     /* allocate memory for capbuf */
  399.     capbuf = cbmem;
  400.  
  401.     /* get the termcap entry */
  402.     switch (tgetent(kbuf, getenv("TERM")))
  403.     {
  404.       case -1:
  405.         write(2, "Can't read /etc/termcap\n", (unsigned)24);
  406. #if OSK
  407.         write(2, "\l", 1);
  408. #endif
  409.         exit(2);
  410.  
  411.       case 0:
  412.         write(2, "Unrecognized TERM type\n", (unsigned)23);
  413. #if OSK
  414.         write(2, "\l", 1);
  415. #endif
  416.         exit(3);
  417.     }
  418. #if 0
  419.     puts(kbuf);
  420.     sleep(3);
  421. #endif
  422.     /* get strings */
  423.     MUSTHAVE(UP, "up");
  424.     MAYHAVE(VB, "vb");
  425.     MUSTHAVE(CM, "cm");
  426.     PAIR(SO, SE, "so", "se");
  427.     PAIR(TI, TE, "ti", "te");
  428.     if (tgetnum("ug") <= 0)
  429.     {
  430.         PAIR(US, UE, "us", "ue");
  431.         PAIR(MD, ME, "md", "me");
  432.  
  433.         /* get italics, or have it default to underline */
  434.         PAIR(AS, AE, "as", "ae");
  435.         if (!*AS)
  436.         {
  437.             AS = US;
  438.             AE = UE;
  439.         }
  440.     }
  441.     MAYHAVE(AL, "al");
  442.     MAYHAVE(DL, "dl");
  443.     MUSTHAVE(CE, "ce");
  444.     MAYHAVE(CD, "cd");
  445. #if OSK
  446.     MAYHAVE(SR_, "sr");
  447. #else    
  448.     MAYHAVE(SR, "sr");
  449. #endif
  450.     PAIR(IM, EI, "im", "ei");
  451.     MAYHAVE(IC, "ic");
  452.     MAYHAVE(DC, "dc");
  453.  
  454.     /* other termcap stuff */
  455.     AM = tgetflag("am");
  456.     PT = tgetflag("pt");
  457.     getsize(0);
  458.  
  459.     /* Key sequences */
  460.     PAIR(KS, KE, "ks", "ke");
  461.     MAYHAVE(KU, "ku");        /* up */
  462.     MAYHAVE(KD, "kd");        /* down */
  463.     MAYHAVE(KL, "kl");        /* left */
  464.     MAYHAVE(KR, "kr");        /* right */
  465.     MAYHAVE(PU, "kP");        /* PgUp */
  466.     MAYHAVE(PD, "kN");        /* PgDn */
  467.     MAYHAVE(HM, "kh");        /* Home */
  468.     MAYHAVE(EN, "kH");        /* End */
  469. #ifndef CRUNCH
  470.     if (!PU) MAYHAVE(PU, "K2");    /* "3x3 pad" names for PgUp, etc. */
  471.     if (!PD) MAYHAVE(PD, "K5");
  472.     if (!HM) MAYHAVE(HM, "K1");
  473.     if (!EN) MAYHAVE(EN, "K4");
  474.  
  475.     MAYHAVE(PU, "PU");        /* old XENIX names for PgUp, etc. */
  476.     MAYHAVE(PD, "PD");        /* (overrides others, if used.) */
  477.     MAYHAVE(HM, "HM");
  478.     MAYHAVE(EN, "EN");
  479. #endif
  480.  
  481. #ifndef NO_CURSORSHAPE
  482.     /* cursor shapes */
  483.     CQ = tgetstr("cQ", &capbuf);
  484.     if (has_CQ)
  485.     {
  486.         CX = tgetstr("cX", &capbuf);
  487.         if (!CX) CX = CQ;
  488.         CV = tgetstr("cV", &capbuf);
  489.         if (!CV) CV = CQ;
  490.         CI = tgetstr("cI", &capbuf);
  491.         if (!CI) CI = CQ;
  492.         CR = tgetstr("cR", &capbuf);
  493.         if (!CR) CR = CQ;
  494.     }
  495. # ifndef CRUNCH
  496.     else
  497.     {
  498.         PAIR(CQ, CV, "ve", "vs");
  499.         CX = CI = CR = CQ;
  500.     }
  501. # endif /* !CRUNCH */
  502. #endif /* !NO_CURSORSHAPE */
  503.  
  504. #undef MUSTHAVE
  505. #undef MAYHAVE
  506. #undef PAIR
  507. }
  508.  
  509.  
  510. /* This function gets the window size.  It uses the TIOCGWINSZ ioctl call if
  511.  * your system has it, or tgetnum("li") and tgetnum("co") if it doesn't.
  512.  * This function is called once during initialization, and thereafter it is
  513.  * called whenever the SIGWINCH signal is sent to this process.
  514.  */
  515. int getsize(signo)
  516.     int    signo;
  517. {
  518.     int    lines;
  519.     int    cols;
  520. #ifdef TIOCGWINSZ
  521.     struct winsize size;
  522. #endif
  523.  
  524. #ifdef SIGWINCH
  525.     /* reset the signal vector */
  526.     signal(SIGWINCH, getsize);
  527. #endif
  528.  
  529.     /* get the window size, one way or another. */
  530.     lines = cols = 0;
  531. #ifdef TIOCGWINSZ
  532.     if (ioctl(2, TIOCGWINSZ, &size) >= 0)
  533.     {
  534.         lines = size.ws_row;
  535.         cols = size.ws_col;
  536.     }
  537. #endif
  538.     if ((lines == 0 || cols == 0) && signo == 0)
  539.     {
  540.         LINES = CHECKBIOS(v_rows(), tgetnum("li"));
  541.         COLS = CHECKBIOS(v_cols(), tgetnum("co"));
  542.     }
  543.     if (lines >= 2 && cols >= 30)
  544.     {
  545.         LINES = lines;
  546.         COLS = cols;
  547.     }
  548.  
  549.     /* Make sure we got values that we can live with */
  550.     if (LINES < 2 || COLS < 30)
  551.     {
  552.         write(2, "Screen too small\n", (unsigned)17);
  553. #if OSK
  554.         write(2, "\l", 1);
  555. #endif
  556.         endwin();
  557.         exit(2);
  558.     }
  559.  
  560.     /* !!! copy the new values into Elvis' options */
  561.     {
  562.         extern char    o_columns[], o_lines[];
  563.  
  564.         *o_columns = COLS;
  565.         *o_lines = LINES;
  566.     }
  567.  
  568.     return 0;
  569. }
  570.  
  571.  
  572. /* This is a function version of addch() -- it is used by tputs() */
  573. int faddch(ch)
  574.     int    ch;
  575. {
  576.     addch(ch);
  577.  
  578.     return 0;
  579. }
  580.  
  581. /* These functions are equivelent to the macros of the same names... */
  582.  
  583. void qaddstr(str)
  584.     char    *str;
  585. {
  586.     REG char *s_, *d_;
  587.  
  588. #if MSDOS
  589.     if (o_pcbios[0])
  590.     {
  591.         while (*str)
  592.             qaddch(*str++);
  593.         return;
  594.     }
  595. #endif
  596.     for (s_=(str), d_=stdscr; *d_++ = *s_++; )
  597.     {
  598.     }
  599.     stdscr = d_ - 1;
  600. }
  601.  
  602. void attrset(a)
  603.     int    a;
  604. {
  605.     do_aend();
  606.     if (a == A_BOLD)
  607.     {
  608.         do_MD();
  609.         aend = ME;
  610.     }
  611.     else if (a == A_UNDERLINE)
  612.     {
  613.         do_US();
  614.         aend = UE;
  615.     }
  616.     else if (a == A_ALTCHARSET)
  617.     {
  618.         do_AS();
  619.         aend = AE;
  620.     }
  621.     else
  622.     {
  623.         aend = "";
  624.     }
  625. }
  626.  
  627.  
  628. void insch(ch)
  629.     int    ch;
  630. {
  631.     if (has_IM)
  632.         do_IM();
  633.     do_IC();
  634.     qaddch(ch);
  635.     if (has_EI)
  636.         do_EI();
  637. }
  638.  
  639. #if MSDOS
  640.  
  641. static int alarmtime;
  642.  
  643. /* raw read - #defined to read (0, ...) on non-MSDOS.
  644.  * With MSDOS, am maximum of 1 byte is read.
  645.  * If more bytes should be read, just change the loop.
  646.  * The following code uses the IBM-PC-System-Timer, so probably wont't work
  647.  * on non-compatibles.
  648.  */
  649. /*ARGSUSED*/
  650. ttyread(buf, len)
  651.     char *buf;
  652.     int len;
  653. {
  654.     volatile char far *biostimer;
  655.     char oldtime;
  656.     int nticks = 0;
  657.     int pos = 0;
  658.  
  659.     biostimer = (char far *)0x0040006cl;
  660.     oldtime = *biostimer;
  661.  
  662.     while (!pos && (!alarmtime || nticks<alarmtime))
  663.     {    if (kbhit())
  664.             if ((buf[pos++] = getch()) == 0) /* function key */
  665.                 buf[pos-1] = '#';
  666.         if (oldtime != *biostimer)
  667.         {    nticks++;
  668.             oldtime = *biostimer;
  669.         }
  670.     }
  671.     return pos;
  672. }
  673.  
  674. alarm(time)
  675.     int time;
  676. {
  677.     alarmtime = 2 * time;        /* ticks are 1/18 sec. */
  678. }
  679.  
  680. sleep(seconds)
  681.     unsigned seconds;
  682. {
  683.     volatile char    far *biostimer = (char far *)0x0040006cl;
  684.     char        stop;
  685.  
  686.     stop = *biostimer + 18 * seconds;
  687.     while (*biostimer != stop)
  688.     {
  689.     }
  690. }
  691. #endif
  692.  
  693. #if TOS
  694.  
  695. static int alarmtime;
  696. static long timer;
  697.  
  698. static gettime()
  699. {
  700.     timer = *(long *)(0x4ba);
  701. }
  702.  
  703. /*ARGSUSED*/
  704. ttyread(buf, len)
  705.     char *buf;
  706.     int len;
  707. {
  708.     int    pos=0;
  709.     long    l;
  710.     long    endtime;
  711.  
  712.     Supexec(gettime);
  713.     endtime = timer+alarmtime;
  714.  
  715.     while (!pos && (!alarmtime || timer<endtime))
  716.     {
  717.         if (Bconstat(2))
  718.         {
  719.             l = Bconin(2);
  720.             if ((buf[pos++]=l) == '\0')
  721.             {
  722.                 buf[pos-1]='#';
  723.                 buf[pos++]=l>>16;
  724.             }
  725.         }
  726.         Supexec(gettime);
  727.     }
  728.     return pos;
  729. }
  730.  
  731. alarm(time)
  732.     int time;
  733. {
  734.     alarmtime = 50 * time;        /* ticks are 1/200 sec. */
  735. }
  736.  
  737. ttywrite(buf, len)
  738.     char *buf;
  739.     int len;
  740. {
  741.     while (len--)
  742.         Bconout(2, *buf++);
  743. }
  744. #endif
  745.  
  746. #if OSK
  747. ttyread(buf, len)
  748.     char *buf;
  749.     int len;
  750. {
  751.     REG int i;
  752.     if ((i = _gs_rdy(0)) > 0)
  753.         return read(0, buf, i < len ? i : len);
  754.     else
  755.         return read(0, buf, 1);
  756. }
  757.  
  758. alarm(time)
  759.     int time;
  760. {
  761. #define TIME(secs) ((secs << 8) | 0x80000000)
  762.     static int alrmid;
  763.  
  764.     if (time)    
  765.         alrmid = alm_set(SIGQUIT, TIME(time));
  766.     else    
  767.         alm_delete(alrmid);
  768. }
  769. #endif /* OSK */
  770.